package util;

import pojo.IdCard;
import pojo.Student;
import pojo.User;

import java.lang.reflect.Field;
import java.security.InvalidParameterException;

public class ObjectUtil {
    //17大基础数据类型
    private static final String[] JAVA_SIMPE_TYPE = {
            "int", "java.lang.Integer", "String", "java.lang.String",
            "boolean", "java.lang.Boolean", "float", "java.lang.Float",
            "double", "java.lang.Double"
    };
    public static void main(String[] args) throws NoSuchFieldException, InstantiationException, IllegalAccessException {
        IdCard idCard = new IdCard("111111111111111111", "张三", "男", "1999-09-09");
        Student student = new Student(11111, "张三", "eiwwdwd", idCard);
        String[] properties = {"username", "password", "idcard"};
        User user = new User();
        copyProperties(student,user, properties);

        System.out.println(user);
    }

    /**
     * 深拷贝，运用反射
     * @param source
     * @param target
     * @param properties
     * @throws NoSuchFieldException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static void copyProperties(Object source, Object target, String[] properties) throws NoSuchFieldException, InstantiationException, IllegalAccessException {
        if (properties.length == 0) {
            throw new InvalidParameterException("properties数组为空");
        }
        Class<?> sourceClazz = source.getClass();
        Class<?> targetClazz = target.getClass();
        // 遍历properties属性
        for (int i = 0; i < properties.length; i++) {
            String propertiesName = properties[i];
            Field sourceField = sourceClazz.getDeclaredField(propertiesName);
            Field targetField = targetClazz.getDeclaredField(propertiesName);
            if (targetField == null|| sourceField == null){
                break;
            }
            sourceField.setAccessible(true);
            targetField.setAccessible(true);
            Class<?> sourceType = sourceField.getType();
            Class<?> targetType = targetField.getType();
            //判断类型是否一致
            if (!sourceType.equals(targetType)) {
                throw new RuntimeException("类型不一致:" + propertiesName);
            }
            if (jugmentJavaTypeOrNot(sourceType.getTypeName())) {
                //17大基本数据类型就直接赋值
                targetField.set(target, sourceField.get(source));
            }else {
                //引用类型就递归赋值
                Object targetFiledObject = targetType.newInstance();
                targetField.set(target, targetFiledObject);
                dnsCopy(sourceField.get(source), targetFiledObject);
            }
        }
    }

    /**
     * 循环引用拷贝
     *
     * @param source
     * @param target
     * @return
     */
    public static void dnsCopy(Object source, Object target) throws InstantiationException, IllegalAccessException, NoSuchFieldException {
        Class<?> sourceClazz = source.getClass();
        Class<?> targetClazz = target.getClass();
        Field[] sourceClazzFields = sourceClazz.getDeclaredFields();
        for (int i = 0; i < sourceClazzFields.length; i++) {
            Field sourceField = sourceClazzFields[i];
            if (sourceField==null){
                break;
            }
            sourceField.setAccessible(true);
            String sourceFieldName = sourceField.getName();
            Field targetField = targetClazz.getDeclaredField(sourceFieldName);
            if (targetField == null){
                break;
            }
            Class<?> sourceType = sourceField.getType();
            Class<?> targetType = targetField.getType();
            targetField.setAccessible(true);
            if (!sourceType.equals(targetType)) {
                break;
            }
            if (jugmentJavaTypeOrNot(sourceType.getTypeName())) {
                //17大基本数据类型就直接赋值
                targetField.set(target, sourceField.get(source));
            } else {
                //引用类型就递归赋值
                Object targetFiledObject = targetType.newInstance();
                targetField.set(target,targetFiledObject);
                dnsCopy(sourceField.get(source), targetFiledObject);
            }
        }
    }

    /**
     * 判断是不是17大基础数据类型
     * @param parameterType
     * @return
     */
    private static Boolean jugmentJavaTypeOrNot(String parameterType) {
        for (int i = 0; i < JAVA_SIMPE_TYPE.length; i++) {
            String javaSimpleType = JAVA_SIMPE_TYPE[i];
            if (parameterType.equals(javaSimpleType)) {
                return true;
            }
        }
        return false;
    }
}